home *** CD-ROM | disk | FTP | other *** search
/ Sprite 1984 - 1993 / Sprite 1984 - 1993.iso / src / kernel / fs / fsStreamOps.c < prev    next >
Encoding:
C/C++ Source or Header  |  1992-12-19  |  29.6 KB  |  998 lines

  1. /*
  2.  * fsStreamOps.c --
  3.  *
  4.  *    The has procedures for the following stream operations:
  5.  *    Read, Write, IOControl, Close.  Select and attributes functions
  6.  *    are in their own files.
  7.  *
  8.  * Copyright 1987 Regents of the University of California
  9.  * All rights reserved.
  10.  * Permission to use, copy, modify, and distribute this
  11.  * software and its documentation for any purpose and without
  12.  * fee is hereby granted, provided that the above copyright
  13.  * notice appear in all copies.  The University of California
  14.  * makes no representations about the suitability of this
  15.  * software for any purpose.  It is provided "as is" without
  16.  * express or implied warranty.
  17.  */
  18.  
  19. #ifndef lint
  20. static char rcsid[] = "$Header: /cdrom/src/kernel/Cvsroot/kernel/fs/fsStreamOps.c,v 9.34 92/09/22 16:14:29 jhh Exp $ SPRITE (Berkeley)";
  21. #endif not lint
  22.  
  23.  
  24. #include <sprite.h>
  25. #include <fs.h>
  26. #include <fsutil.h>
  27. #include <fsio.h>
  28. #include <fsNameOps.h>
  29. #include <fscache.h>
  30. #include <fsStat.h>
  31. #include <fsdm.h>
  32. #include <fsprefix.h>
  33. #include <rpc.h>
  34. #include <vm.h>
  35. #include <fsrmt.h>
  36. #include <fslcl.h>
  37. #include <assert.h>
  38. #include <machparam.h>
  39. #include <string.h>
  40. #include <fspdev.h>
  41. #include <recov.h>
  42.  
  43. extern Boolean fsconsist_ClientCachingEnabled;
  44.  
  45.  
  46. /*
  47.  *----------------------------------------------------------------------
  48.  *
  49.  * Fs_Read --
  50.  *
  51.  *    Read from a stream.  The main jobs of this routine are to
  52.  *    set things up for (remote) waiting, and to branch out to
  53.  *    the procedure that implements Read for the type of the stream.
  54.  *    If the server is down, or the stream's handle has gone stale,
  55.  *    this blocks the process while waiting for handle recovery.
  56.  *    Also, the stream access position is maintained by this procedure,
  57.  *    even though the read offset is an explicit argument.
  58.  *
  59.  * Results:
  60.  *    A return status, SUCCESS if successful.
  61.  *
  62.  * Side effects:
  63.  *    The buffer is filled with the number of bytes indicated by
  64.  *    the length parameter.  The in/out length parameter specifies
  65.  *    the buffer size on input and is updated to reflect the number
  66.  *    of bytes actually read.
  67.  *
  68.  *----------------------------------------------------------------------
  69.  */
  70. ReturnStatus
  71. Fs_Read(streamPtr, buffer, offset, lenPtr)
  72.     Fs_Stream     *streamPtr;    /* Stream to read from. */
  73.     Address     buffer;        /* Where to read into. */
  74.     int     offset;        /* Where to start reading from. */
  75.     int     *lenPtr;    /* Contains number of bytes to read on input,
  76.                    and is filled with number of bytes read. */
  77. {
  78.     register ReturnStatus     status = SUCCESS;
  79.     Sync_RemoteWaiter        remoteWaiter;
  80.     Fs_IOParam            io;
  81.     register Fs_IOParam     *ioPtr = &io;
  82.     Fs_IOReply            reply;
  83.     int                streamType;
  84.     register int        toRead;
  85.     int                amtRead;
  86.  
  87.     toRead = *lenPtr;
  88.     *lenPtr = 0;
  89.     amtRead = 0;
  90.     if (sys_ShuttingDown) {
  91.     return(FAILURE);
  92.     } else if ((streamPtr->flags & FS_READ) == 0) {
  93.     return(FS_NO_ACCESS);
  94.     } else if (toRead == 0) {
  95.     return(SUCCESS);
  96.     } else if ((toRead < 0) || (offset < 0)) {
  97.     return(GEN_INVALID_ARG);
  98.     } else if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
  99.     return(FS_STALE_HANDLE);
  100.     }
  101.     streamType = streamPtr->ioHandlePtr->fileID.type;
  102.  
  103.     FsSetIOParam(ioPtr, buffer, toRead, offset, streamPtr->flags);
  104.     reply.length = 0;
  105.     reply.flags = 0;
  106.     reply.signal = 0;
  107.     reply.code = 0;
  108.  
  109.     /*
  110.      * Outer loop to attempt the read and then block if no data is ready.
  111.      * The loop terminates upon error or if any data is transferred.
  112.      */
  113.     remoteWaiter.hostID = rpc_SpriteID;
  114.     while (TRUE) {
  115.     Sync_GetWaitToken(&remoteWaiter.pid, &remoteWaiter.waitToken);
  116.  
  117.     status = (fsio_StreamOpTable[streamType].read) (streamPtr,
  118.             ioPtr, &remoteWaiter, &reply);
  119. #ifdef lint
  120.     status = Fsio_FileRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  121.     status = FsrmtFileRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  122.     status = Fsio_DeviceRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  123.     status = Fsio_PipeRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  124.     status = FspdevControlRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  125.     status = FspdevServerStreamRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  126.     status = FspdevPseudoStreamRead(streamPtr, ioPtr, &remoteWaiter, &reply);
  127.     status = Fsrmt_Read(streamPtr, ioPtr, &remoteWaiter, &reply);
  128. #endif
  129.     if (status == SUCCESS) {
  130.         if (streamType == FSIO_RMT_DEVICE_STREAM ||
  131.             streamType == FSIO_RMT_PIPE_STREAM ||
  132.             streamType == FSIO_RMT_PSEUDO_STREAM ||
  133.             streamType == FSIO_RMT_PFS_STREAM ||
  134.             streamType == FSIO_RMT_CONTROL_STREAM) {
  135.         fs_Stats.rmtIO.remoteDevicishBytesRead += reply.length;
  136.         }
  137.         break;
  138.     } else if (status == FS_WOULD_BLOCK && 
  139.         (streamPtr->flags & FS_NON_BLOCKING) == 0) {
  140.         /*
  141.          * File streams will return FS_WOULD_BLOCK when waiting for a
  142.          * cache block, but stuff has already been returned.  We want
  143.          * to wait instead of returning.
  144.          */
  145.         if ((reply.length > 0) && (streamType != FSIO_LCL_FILE_STREAM) &&
  146.             (streamType != FSIO_RMT_FILE_STREAM)) {
  147.         /*
  148.          * Stream routine ought not do return FS_WOULD_BLOCK
  149.          * in this case, but we cover for it here.
  150.          */
  151.         status = SUCCESS;
  152.         break;
  153.         } else { 
  154.         if (reply.length > 0) {
  155.             /*
  156.              * A cache block is unavailable, but data has already
  157.              * been returned. Update the read request to start
  158.              * with the unavailable block.
  159.              */
  160.             toRead -= reply.length;
  161.             FsSetIOParam(ioPtr, io.buffer + reply.length, 
  162.             toRead, io.offset + reply.length, streamPtr->flags);
  163.         }
  164.         if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  165.             status = GEN_ABORTED_BY_SIGNAL;
  166.             break;
  167.         }
  168.         }
  169.     } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  170.                status == RPC_SERVICE_DISABLED)  {
  171.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  172.         if (status != SUCCESS) {
  173.         break;
  174.         }
  175.     } else {
  176.         if (status == FS_WOULD_BLOCK && reply.length > 0) {
  177.         /*
  178.          * Cannot return FS_WOULD_BLOCK if some data was read.
  179.          */
  180.         status = SUCCESS;
  181.         }
  182.         break;
  183.     }
  184.     /*
  185.      * Restore the length parameter because it may have been set to
  186.      * zero when the read blocked.
  187.      */
  188.     ioPtr->length = toRead;
  189.     amtRead += reply.length;
  190.     }
  191.  
  192.     amtRead += reply.length;
  193.     /*
  194.      * Cache the file offset for sequential access.
  195.      */
  196.     streamPtr->offset += amtRead;
  197.     *lenPtr = amtRead;
  198.  
  199.     if (status == FS_BROKEN_PIPE) {
  200.     Sig_Send(SIG_PIPE, 0, PROC_MY_PID, FALSE, (Address)0);
  201.     } else if (reply.signal != 0) {
  202.     Sig_Send(reply.signal, reply.code, PROC_MY_PID, FALSE, (Address)0);
  203.     }
  204.     return(status);
  205. }
  206.  
  207.  
  208. /*
  209.  *----------------------------------------------------------------------
  210.  *
  211.  * Fs_Write --
  212.  *
  213.  *    Write to a stream.  This sets up for (remote) waiting and then
  214.  *    branches to the routine that implements writing for the stream.
  215.  *    If the server is down, or the streams handle has gone stale,
  216.  *    this will block the process while waiting for handle recovery.
  217.  *    Finally, the stream access position of the stream is maintained
  218.  *    even though the write offset is an explicit parameter.
  219.  *
  220.  * Results:
  221.  *    A return status, SUCCESS if successful.
  222.  *
  223.  * Side effects:
  224.  *    The data in the buffer is written to the file at the indicated offset.
  225.  *    The in/out length parameter specifies the amount of data to write
  226.  *    and is updated to reflect the number of bytes actually written.
  227.  *    The stream offset field is updated to after the bytes written.
  228.  *
  229.  *----------------------------------------------------------------------
  230.  */
  231. ReturnStatus
  232. Fs_Write(streamPtr, buffer, offset, lenPtr)
  233.     Fs_Stream *streamPtr;        /* The stream to write to */
  234.     Address buffer;            /* The buffer to fill in */
  235.     int offset;                /* Where in the stream to write to */
  236.     int *lenPtr;            /* In/Out byte count */
  237. {
  238.     register ReturnStatus     status = SUCCESS;    /* I/O return status */
  239.     Sync_RemoteWaiter    remoteWaiter;        /* Process info for waiting */
  240.     Fs_IOParam        io;            /* Write parameter block */
  241.     register Fs_IOParam *ioPtr = &io;
  242.     Fs_IOReply        reply;            /* Return length, signal */
  243.     int            toWrite;        /* Amount remaining to write.
  244.                          * Keep our own copy because
  245.                          * lower-levels may modify
  246.                          * ioPtr->length */
  247.     register int    amountWritten;        /* Amount transferred */
  248.     int            streamType;        /* Type from I/O handle */
  249.  
  250.     toWrite = *lenPtr;
  251.     amountWritten = 0;
  252.     *lenPtr = 0;
  253.     if (sys_ShuttingDown) {
  254.     return(FAILURE);
  255.     } else if ((streamPtr->flags & FS_WRITE) == 0) {
  256.     return(FS_NO_ACCESS);
  257.     } else if (toWrite == 0) {
  258.     return(SUCCESS);
  259.     } else if ((toWrite < 0) || (offset < 0)) {
  260.     return(GEN_INVALID_ARG);
  261.     } else if (!Fsutil_HandleValid(streamPtr->ioHandlePtr)) {
  262.     return(FS_STALE_HANDLE);
  263.     }
  264.     streamType = streamPtr->ioHandlePtr->fileID.type;
  265.  
  266.     FsSetIOParam(ioPtr, buffer, toWrite, offset, streamPtr->flags);
  267.     reply.length = 0;
  268.     reply.flags = 0;
  269.     reply.signal = 0;
  270.     reply.code = 0;
  271.  
  272.     remoteWaiter.hostID = rpc_SpriteID;
  273.  
  274.     /*
  275.      * Main write loop.  This handles partial writes, non-blocking streams,
  276.      * and crash recovery.  This loop expects the stream write procedure to
  277.      * return FS_WOULD_BLOCK if it transfers no data, and lets it return
  278.      * either SUCCESS or FS_WOULD_BLOCK on partial writes.  SUCCESS with a
  279.      * partial write makes this loop return.
  280.      * If a stream write procedure returns FS_WOULD_BLOCK is is required to
  281.      * have put the remoteWaiter information on an appropriate wait list.
  282.      * This loop ensures that a non-blocking stream returns SUCCESS if some
  283.      * data is transferred, and FS_WOULD_BLOCK if none can be transferred now.
  284.      */
  285.     while (TRUE) {
  286.     Sync_GetWaitToken(&remoteWaiter.pid, &remoteWaiter.waitToken);
  287.  
  288.     status = (fsio_StreamOpTable[streamType].write) (streamPtr, ioPtr,
  289.                               &remoteWaiter, &reply);
  290. #ifdef lint
  291.     status = Fsio_FileWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  292.     status = FsrmtFileWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  293.     status = Fsio_DeviceWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  294.     status = Fsio_PipeWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  295.     status = FspdevPseudoStreamWrite(streamPtr, ioPtr, &remoteWaiter, &reply);
  296.     status = Fsrmt_Write(streamPtr, ioPtr, &remoteWaiter, &reply);
  297. #endif
  298.     toWrite -= reply.length;
  299.     amountWritten += reply.length;
  300.     /*
  301.      * Reset pointers because stream-specific routine may have
  302.      * modified them arbitrarily.
  303.      */
  304.     ioPtr->buffer = buffer + amountWritten;
  305.     ioPtr->offset = offset + amountWritten;
  306.     ioPtr->length = toWrite;
  307.     if (status == SUCCESS) {
  308.         if (streamType == FSIO_RMT_DEVICE_STREAM ||
  309.             streamType == FSIO_RMT_PIPE_STREAM ||
  310.             streamType == FSIO_RMT_PSEUDO_STREAM ||
  311.             streamType == FSIO_RMT_PFS_STREAM ||
  312.             streamType == FSIO_RMT_CONTROL_STREAM) {
  313.         fs_Stats.rmtIO.remoteDevicishBytesWritten += reply.length;
  314.         }
  315.         break;
  316.     } else if (status == FS_WOULD_BLOCK) {
  317.         if ((streamPtr->flags & FS_NON_BLOCKING) == 0) {
  318.         if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  319.             status = GEN_ABORTED_BY_SIGNAL;
  320.             break;
  321.         }
  322.         } else {
  323.         if (amountWritten > 0) {
  324.             status = SUCCESS;    /* non-blocking partial write */
  325.         }
  326.         break;
  327.         }
  328.     } else if (status == RPC_TIMEOUT || status == FS_STALE_HANDLE ||
  329.                status == RPC_SERVICE_DISABLED)  {
  330.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  331.         if (status != SUCCESS) {
  332.         break;
  333.         }
  334.     } else {
  335.         break;            /* stream error */
  336.     }
  337.     }
  338.     /*
  339.      * Return info about the transfer.
  340.      */
  341.     *lenPtr = amountWritten;
  342.     streamPtr->offset += amountWritten;
  343.     if (status == FS_BROKEN_PIPE) {
  344.     Sig_Send(SIG_PIPE, 0, PROC_MY_PID, FALSE, (Address)0);
  345.     } else if (reply.signal != 0) {
  346.     Sig_Send(reply.signal, reply.code, PROC_MY_PID, FALSE, (Address)0);
  347.     }
  348.  
  349.     return(status);
  350. }
  351.  
  352. /*
  353.  *----------------------------------------------------------------------
  354.  *
  355.  * Fs_IOControl --
  356.  *
  357.  *    Generic IOControl handler.  This will also propogate ALL
  358.  *    IOControls down to lower levels, mainly so that pseudo-device
  359.  *    drivers (user-level server programs) will see all of them.
  360.  *
  361.  * Results:
  362.  *    An error code that depends in the command
  363.  *
  364.  * Side effects:
  365.  *    Command specific
  366.  *
  367.  *----------------------------------------------------------------------
  368.  */
  369.  
  370. ReturnStatus
  371. Fs_IOControl(streamPtr, ioctlPtr, replyPtr)
  372.     register Fs_Stream *streamPtr;
  373.     Fs_IOCParam *ioctlPtr;        /* I/O Control parameter block */
  374.     Fs_IOReply *replyPtr;        /* Return length and signal */
  375. {
  376.     register ReturnStatus    status;
  377.     register Boolean        retry;
  378.     register int        command = ioctlPtr->command;
  379.     int                offset;
  380.     Ioc_LockArgs        *lockArgsPtr;
  381.     register int        streamType;
  382.  
  383.     lockArgsPtr = (Ioc_LockArgs *) NIL;
  384.     /*
  385.      * Retry loop to handle server error recovery and blocking locks.
  386.      */
  387.     streamType = streamPtr->ioHandlePtr->fileID.type;
  388.     do {
  389.     if (!Fsutil_HandleValid((Fs_HandleHeader *)streamPtr) ||
  390.         !Fsutil_HandleValid((Fs_HandleHeader *)streamPtr->ioHandlePtr)) {
  391.         return(FS_STALE_HANDLE);
  392.     }
  393.     retry = FALSE;
  394.     replyPtr->length = ioctlPtr->outBufSize;
  395.     replyPtr->flags = 0;
  396.     replyPtr->signal = 0;
  397.     replyPtr->code = 0;
  398.     /*
  399.      * Pre-processing for some of the IOControls.
  400.      *
  401.      * IOC_NUM_READABLE.  We pass the stream offset
  402.      * down using the inBuffer so that the stream-type-specific routines
  403.      * can correctly compute how much data is available.  (Still have to
  404.      * do this even though we pass the streamPtr down because the offset
  405.      * on the server may not be up-to-date.  Probably fixable.)
  406.      *
  407.      * IOC_LOCK and IOC_UNLOCK.  We have to fill in the process and hostID
  408.      * entries in the buffer passed in from the user.
  409.      *
  410.      * IOC_PREFIX.  This is processed here and not passed down to
  411.      * lower levels.  This looks at the streamPtr->nameInfoPtr which
  412.      * is completely generic and not otherwise needed by lower levels.
  413.      * This simplifies the object modules and eliminates an RPC in the
  414.      * case that the object is remote.
  415.      */
  416.     if (command == IOC_NUM_READABLE) {
  417.         offset = streamPtr->offset;
  418.         ioctlPtr->inBuffer = (Address) &offset;
  419.         ioctlPtr->inBufSize = sizeof(int);
  420.         ioctlPtr->flags &= ~FS_USER_IN;
  421.     } else if (command == IOC_LOCK || command == IOC_UNLOCK) {
  422.         lockArgsPtr = (Ioc_LockArgs *)ioctlPtr->inBuffer;
  423.         lockArgsPtr->hostID = rpc_SpriteID;
  424.         Sync_GetWaitToken(&lockArgsPtr->pid, &lockArgsPtr->token);
  425.     } else if (command == IOC_PREFIX) {
  426.         Fsprefix    *prefixPtr;
  427.         if ((streamPtr->nameInfoPtr == (Fs_NameInfo *) NIL) ||
  428.         (streamPtr->nameInfoPtr->prefixPtr == (Fsprefix *)NIL)) {
  429.         status = GEN_INVALID_ARG;
  430.         } else {
  431.         prefixPtr = streamPtr->nameInfoPtr->prefixPtr;
  432.         if (ioctlPtr->outBufSize < prefixPtr->prefixLength) {
  433.             status = GEN_INVALID_ARG;
  434.         } else {
  435.             (void) strcpy(ioctlPtr->outBuffer, prefixPtr->prefix);
  436.             replyPtr->length = prefixPtr->prefixLength + 1;
  437.             status = SUCCESS;
  438.         }
  439.         }
  440.         return(status);    /* Do not pass down IOC_PREFIX */
  441.     }
  442.  
  443.     status = (*fsio_StreamOpTable[streamType].ioControl)
  444.             (streamPtr, ioctlPtr, replyPtr);
  445. #ifdef lint
  446.     status = Fsio_FileIOControl(streamPtr, ioctlPtr, replyPtr);
  447.     status = FsrmtFileIOControl(streamPtr, ioctlPtr, replyPtr);
  448.     status = Fsio_DeviceIOControl(streamPtr, ioctlPtr, replyPtr);
  449.     status = Fsrmt_IOControl(streamPtr, ioctlPtr, replyPtr);
  450.     status = Fsio_PipeIOControl(streamPtr, ioctlPtr, replyPtr);
  451.     status = FspdevControlIOControl(streamPtr, ioctlPtr, replyPtr);
  452.     status = FspdevServerStreamIOControl(streamPtr, ioctlPtr, replyPtr);
  453.     status = FspdevPseudoStreamIOControl(streamPtr, ioctlPtr, replyPtr);
  454. #endif /* lint */
  455.  
  456.     switch(status) {
  457.         case SUCCESS:
  458.         break;
  459.         case RPC_TIMEOUT:
  460.         case RPC_SERVICE_DISABLED:
  461.         case FS_STALE_HANDLE:
  462.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  463.         if (status == SUCCESS) {
  464.             retry = TRUE;
  465.             break;
  466.         } else {
  467.             return(status);
  468.         }
  469.         case FS_WOULD_BLOCK:
  470.         /*
  471.          * Blocking I/O control.  Should be a lock, although some
  472.          * pseudo-device servers (like ipServer) will return
  473.          * this status code for their own reasons.
  474.          */
  475.         if ((command == IOC_LOCK) &&
  476.             ((lockArgsPtr->flags & IOC_LOCK_NO_BLOCK) == 0)) {
  477.             if (Sync_ProcWait((Sync_Lock *) NIL, TRUE)) {
  478.             return(GEN_ABORTED_BY_SIGNAL);
  479.             } else {
  480.             retry = TRUE;
  481.             break;
  482.             }
  483.         } else {
  484.             return(status);
  485.         }
  486.         default:
  487.         return(status);
  488.     }
  489.     } while (retry);
  490.  
  491.     /*
  492.      * Do generic I/O controls that affect streams -
  493.      * flag manipulation, and offset seeking.
  494.      */
  495.     switch (command) {
  496.     case IOC_REPOSITION: {
  497.         /*
  498.          * Set the read/write offset of the stream.
  499.          */
  500.         register int newOffset;
  501.         register Ioc_RepositionArgs    *iocArgsPtr;
  502.  
  503.         if (ioctlPtr->inBuffer == (Address)NIL) {
  504.         status = GEN_INVALID_ARG;
  505.         break;
  506.         }
  507.         iocArgsPtr = (Ioc_RepositionArgs *)ioctlPtr->inBuffer;
  508.         newOffset = -1;
  509.         switch(iocArgsPtr->base) {
  510.         case IOC_BASE_ZERO:
  511.             newOffset = iocArgsPtr->offset;
  512.             break;
  513.         case IOC_BASE_CURRENT:
  514.             newOffset = streamPtr->offset + iocArgsPtr->offset;
  515.             break;
  516.         case IOC_BASE_EOF: {
  517.             Fs_Attributes attrs;
  518.  
  519.             status = Fs_GetAttrStream(streamPtr, &attrs);
  520.             if (status != SUCCESS) {
  521.             break;
  522.             }
  523.             newOffset = attrs.size + iocArgsPtr->offset;
  524.             break;
  525.         }
  526.         }
  527.         if (newOffset < 0) {
  528.         status = GEN_INVALID_ARG;
  529.         } else {
  530.         if (ioctlPtr->outBuffer != (Address)NIL) {
  531.             *(int *)ioctlPtr->outBuffer = newOffset;
  532.             replyPtr->length = sizeof(int);
  533.         }
  534.         streamPtr->offset = newOffset;
  535.         }
  536.         break;
  537.     }
  538.     /*
  539.      * Stream flags manipulation.  There are the FS_ constants which
  540.      * have a place in the streams flag field, and the IOC_ constants
  541.      * which user programs know about.  These allow flexibility, but
  542.      * requires specific checking for each kernel flag...
  543.      */
  544.     case IOC_GET_FLAGS: {
  545.         /*
  546.          * OR the kernel flags from the stream into the output flags word.
  547.          */
  548.         register int flags = 0;
  549.         if (streamPtr->flags & FS_APPEND) {
  550.         flags |= IOC_APPEND;
  551.         }
  552.         if (streamPtr->flags & FS_NON_BLOCKING) {
  553.         flags |= IOC_NON_BLOCKING;
  554.         }
  555.         if (streamPtr->flags & FS_READ) {
  556.         flags |= IOC_READ;
  557.         }
  558.         if (streamPtr->flags & FS_WRITE) {
  559.         flags |= IOC_WRITE;
  560.         }
  561.         if (ioctlPtr->outBufSize != sizeof(int)) {
  562.         status = GEN_INVALID_ARG;
  563.         } else {
  564.         *(int *)ioctlPtr->outBuffer |= flags;
  565.         replyPtr->length = sizeof(int);
  566.         }
  567.         break;
  568.     }
  569.     case IOC_SET_BITS:
  570.     case IOC_SET_FLAGS: {
  571.         /*
  572.          * Set any kernel stream flags specifid by the IOControl flags.
  573.          * We rely on the file-type IOControl routine to verify
  574.          * the validity of the flag choices.  See that IOC_SET_FLAGS
  575.          * differs from IOC_SET_BITS by turning off any bits that
  576.          * are not in the input word.
  577.          */
  578.         register int flags;
  579.         if (ioctlPtr->inBufSize != sizeof(int)) {
  580.         status = GEN_INVALID_ARG;
  581.         break;
  582.         }
  583.         flags = *(int *)ioctlPtr->inBuffer;
  584.         if ((flags & IOC_APPEND) && (streamPtr->flags & FS_WRITE) == 0) {
  585.         status = FS_NO_ACCESS;
  586.         break;
  587.         }
  588.         if (flags & IOC_APPEND) {
  589.         streamPtr->flags |= FS_APPEND;
  590.         } else if (command == IOC_SET_FLAGS) {
  591.         streamPtr->flags &= ~FS_APPEND;
  592.         }
  593.         if (flags & IOC_NON_BLOCKING) {
  594.         streamPtr->flags |= FS_NON_BLOCKING;
  595.         } else if (command == IOC_SET_FLAGS) {
  596.         streamPtr->flags &= ~FS_NON_BLOCKING;
  597.         }
  598.         break;
  599.     }
  600.     case IOC_CLEAR_BITS:{
  601.         register int flags;
  602.         if (ioctlPtr->inBufSize != sizeof(int)) {
  603.         status = GEN_INVALID_ARG;
  604.         break;
  605.         }
  606.         flags = *(int *)ioctlPtr->inBuffer;
  607.         if (flags & IOC_APPEND) {
  608.         streamPtr->flags &= ~FS_APPEND;
  609.         }
  610.         if (flags & IOC_NON_BLOCKING) {
  611.         streamPtr->flags &= ~FS_NON_BLOCKING;
  612.         }
  613.         break;
  614.     }
  615.     /*
  616.      * Everything for the following has already been handled by
  617.      * the stream specific IOControl routines.
  618.      */
  619.     case IOC_LOCK:
  620.     case IOC_UNLOCK:
  621.     case IOC_NUM_READABLE:
  622.     case IOC_TRUNCATE:
  623.     case IOC_GET_OWNER:
  624.     case IOC_SET_OWNER:
  625.     case IOC_MAP:
  626.          break;
  627.     }
  628.     /*
  629.      * Generate signal returned from stream-specific routine.
  630.      */
  631.     if (replyPtr->signal != 0) {
  632.     Sig_Send(replyPtr->signal, replyPtr->code, PROC_MY_PID, FALSE,
  633.         (Address)0);
  634.     }
  635.     return(status);
  636. }
  637.  
  638. /*
  639.  *----------------------------------------------------------------------
  640.  *
  641.  * Fs_Close --
  642.  *
  643.  *    Free this reference to the Stream.  The reference count is decreased
  644.  *    and when it goes to zero the stream close routine is called
  645.  *    to release the reference to the I/O handle.
  646.  *
  647.  * Results:
  648.  *    None.
  649.  *
  650.  * Side effects:
  651.  *      If the ref count is zero after the decrement,  the reference to
  652.  *      the file is released and the input parameter is free'd.
  653.  *
  654.  *----------------------------------------------------------------------
  655.  */
  656.  
  657. ReturnStatus
  658. Fs_Close(streamPtr)
  659.     register Fs_Stream     *streamPtr;
  660. {
  661.     register ReturnStatus     status;
  662.     Proc_ControlBlock        *procPtr;
  663.     Boolean            retry;
  664.  
  665.     if (streamPtr == (Fs_Stream *)NIL) {
  666.     /*
  667.      * Bomb-proofing.  The current directory sometimes doesn't get
  668.      * found at boot time and so there is a NIL streamPtr around for it.
  669.      */
  670.     return(FS_INVALID_ARG);
  671.     }
  672.     Fsutil_HandleLock(streamPtr);
  673.     procPtr = Proc_GetEffectiveProc();
  674.     if (streamPtr->hdr.refCount > 1) {
  675.     /*
  676.      * There are other copies of the stream (due to fork/dup) so
  677.      * we don't close the I/O handle yet.
  678.      */
  679.     Fsutil_HandleRelease(streamPtr, TRUE);
  680.     return SUCCESS;
  681.     }
  682.     /*
  683.      * Call the stream type close routine to clean up this reference
  684.      * to the I/O handle.
  685.      */
  686.     Fsutil_HandleLock(streamPtr->ioHandlePtr);
  687.  
  688.     do {
  689.     retry = FALSE;
  690.     status = (fsio_StreamOpTable[streamPtr->ioHandlePtr->fileID.type].close)
  691.         (streamPtr, rpc_SpriteID, procPtr->processID, streamPtr->flags,
  692.         0, (ClientData)NIL);
  693. #ifdef lint
  694.     status = Fsio_FileClose(streamPtr, rpc_SpriteID, procPtr->processID,
  695.         streamPtr->flags, 0, (ClientData)NIL);
  696.     status = FsrmtFileClose(streamPtr, rpc_SpriteID, procPtr->processID,
  697.         streamPtr->flags, 0, (ClientData)NIL);
  698.     status = Fsio_PipeClose(streamPtr, rpc_SpriteID, procPtr->processID,
  699.         streamPtr->flags, 0, (ClientData)NIL);
  700.     status = Fsio_DeviceClose(streamPtr, rpc_SpriteID, procPtr->processID,
  701.         streamPtr->flags, 0, (ClientData)NIL);
  702.     status = Fsrmt_IOClose(streamPtr, rpc_SpriteID, procPtr->processID,
  703.         streamPtr->flags, 0, (ClientData)NIL);
  704.     status = FspdevControlClose(streamPtr, rpc_SpriteID, procPtr->processID,
  705.         streamPtr->flags, 0, (ClientData)NIL);
  706.     status = FspdevPseudoStreamClose(streamPtr, rpc_SpriteID,procPtr->processID,
  707.         streamPtr->flags, 0, (ClientData)NIL);
  708.     status = FspdevServerStreamClose(streamPtr, rpc_SpriteID,procPtr->processID,
  709.         streamPtr->flags, 0, (ClientData)NIL);
  710. #endif /* lint */
  711.     /*
  712.      * If the server will recover quickly, then it should be okay
  713.      * to hang here.  We didn't use to.  This is only worth doing in
  714.      * transparent server recovery, where it depends on correct
  715.      * reference counts.  Therefore recov_Transparent must be true
  716.      * for this.  (And must be true on both clients and servers.)
  717.      */
  718.     switch(status) {
  719.     case SUCCESS:
  720.         break;
  721.     case RPC_TIMEOUT:
  722.     case RPC_SERVICE_DISABLED:
  723.     case FS_STALE_HANDLE:
  724.         status = Fsutil_WaitForRecovery(streamPtr->ioHandlePtr, status);
  725.         if (status == SUCCESS) {
  726.         retry = TRUE;
  727.         break;
  728.         } else {
  729.         return(status);
  730.         }
  731.     default:
  732.         break;
  733.     }
  734.     } while (retry && recov_Transparent);
  735.  
  736.     if (Fsio_StreamClientClose(&streamPtr->clientList, rpc_SpriteID)) {
  737.     Fsio_StreamDestroy(streamPtr);
  738.     } else {
  739.     Fsutil_HandleRelease(streamPtr, TRUE);
  740.     }
  741.     return(status);
  742. }
  743.  
  744.  
  745. /*
  746.  *----------------------------------------------------------------------
  747.  *
  748.  * Fs_CheckSetID --
  749.  *
  750.  *    Determine if the given stream has the set uid or set gid bits set.
  751.  *
  752.  * Results:
  753.  *    None.
  754.  *
  755.  * Side effects:
  756.  *    *uidPtr and *gidPtr set to -1 if the respective bit isn't set and set
  757.  *    to the uid and/or gid of the file otherwise.
  758.  *
  759.  *----------------------------------------------------------------------
  760.  */
  761. void
  762. Fs_CheckSetID(streamPtr, uidPtr, gidPtr)
  763.     Fs_Stream    *streamPtr;
  764.     int        *uidPtr;
  765.     int        *gidPtr;
  766. {
  767.     register    Fscache_Attributes    *cachedAttrPtr;
  768.  
  769.     switch (streamPtr->ioHandlePtr->fileID.type) {
  770.     case FSIO_LCL_FILE_STREAM:
  771.         cachedAttrPtr =
  772.            &((Fsio_FileIOHandle *)streamPtr->ioHandlePtr)->cacheInfo.attr;
  773.         break;
  774.     case FSIO_RMT_FILE_STREAM:
  775.         cachedAttrPtr =
  776.            &((Fsrmt_FileIOHandle *)streamPtr->ioHandlePtr)->cacheInfo.attr;
  777.         break;
  778.     case FSIO_LCL_PFS_STREAM:
  779.     case FSIO_RMT_PFS_STREAM:
  780.         /* Could do get attributes request to the PFS here
  781.          * but in general it could be a security hole so  
  782.          * we won't allow setuid or setgid programs in a PFS. JMS.
  783.          */
  784.         cachedAttrPtr = (Fscache_Attributes *)NIL;
  785.         break;
  786.     default:
  787.         panic( "Fs_CheckSetID, wrong stream type\n",
  788.         streamPtr->ioHandlePtr->fileID.type);
  789.         return;
  790.     }
  791.     if ((cachedAttrPtr != (Fscache_Attributes *)NIL) &&
  792.     (cachedAttrPtr->permissions & FS_SET_UID)) {
  793.     *uidPtr = cachedAttrPtr->uid;
  794.     } else {
  795.     *uidPtr = -1;
  796.     }
  797.     if ((cachedAttrPtr != (Fscache_Attributes *)NIL) &&
  798.     (cachedAttrPtr->permissions & FS_SET_GID)) {
  799.     *gidPtr = cachedAttrPtr->gid;
  800.     } else {
  801.     *gidPtr = -1;
  802.     }
  803. }
  804.  
  805. /*
  806.  *----------------------------------------------------------------------
  807.  *
  808.  * Fs_FileWriteBackStub --
  809.  *
  810.  *      This is the stub for the Fs_WriteBackID system call.
  811.  *    The byte arguments are rounded to blocks, and the range of
  812.  *    blocks that covers the byte range is written back out of the cache.
  813.  *
  814.  * Results:
  815.  *    A return status or SUCCESS if successful.
  816.  *
  817.  * Side effects:
  818.  *    Write out the range of blocks in the cache.
  819.  *
  820.  *----------------------------------------------------------------------
  821.  */
  822. ReturnStatus
  823. Fs_FileWriteBackStub(streamID, firstByte, lastByte, shouldBlock)
  824.     int        streamID;    /* Stream ID of file to write back. */
  825.     int        firstByte;    /* First byte to write back. */
  826.     int        lastByte;    /* Last byte to write back. */
  827.     Boolean    shouldBlock;    /* TRUE if should wait for the blocks to go
  828.                  * to disk. */
  829. {
  830.     Ioc_WriteBackArgs args;
  831.  
  832.     args.firstByte = firstByte;
  833.     args.lastByte = lastByte;
  834.     args.shouldBlock = shouldBlock;
  835.  
  836.     return( Fs_IOControlStub(streamID, IOC_WRITE_BACK, sizeof(args),
  837.                     (Address)&args, 0, (Address)0) );
  838. }
  839.  
  840. /*
  841.  *----------------------------------------------------------------------
  842.  *
  843.  * Fs_FileBeingMapped --
  844.  *
  845.  *      This is called by VM when a file is being mapped into
  846.  *    a user's virtual address (yuck, blech), or is being
  847.  *    unmapped from the address space.  This does a
  848.  *    write-back/invalidate so that the file is not cached
  849.  *    by FS any longer.  This ensures that paging traffic
  850.  *    wont get stale data.
  851.  *
  852.  * Results:
  853.  *    A return status or SUCCESS if successful.
  854.  *
  855.  * Side effects:
  856.  *    Write out the range of blocks in the cache.
  857.  *
  858.  *----------------------------------------------------------------------
  859.  */
  860. ReturnStatus
  861. Fs_FileBeingMapped(streamPtr, isMapped)
  862.     Fs_Stream *streamPtr;    /* Open stream being mapped in */
  863.     int        isMapped;    /* 1 if file is being mapped. */
  864. {
  865.     ReturnStatus status = SUCCESS;
  866. #if 0    
  867.     Fscache_FileInfo    *cacheInfoPtr;
  868. #endif    
  869.     Fs_IOCParam    ioctl;
  870.     Fs_IOReply    reply;
  871.  
  872.     if (isMapped) {
  873.     /*
  874.      * THIS IS BOGUS.  The whole thing should be done via I/O control
  875.      * so this routine isn't polluted with checks against the stream type.
  876.      */
  877.     switch(streamPtr->ioHandlePtr->fileID.type) {
  878.         case FSIO_LCL_FILE_STREAM: {
  879. #if 0
  880.         register Fsio_FileIOHandle *localHandlePtr;
  881.         localHandlePtr = (Fsio_FileIOHandle *)streamPtr->ioHandlePtr;
  882.         cacheInfoPtr = &localHandlePtr->cacheInfo;
  883. #endif
  884.         break;
  885.         }
  886.         case FSIO_RMT_FILE_STREAM: {
  887. #if 0        
  888.         register Fsrmt_FileIOHandle *rmtHandlePtr;
  889.         rmtHandlePtr = (Fsrmt_FileIOHandle *)streamPtr->ioHandlePtr;
  890.         cacheInfoPtr = &rmtHandlePtr->cacheInfo;
  891. #endif        
  892.         break;
  893.         }
  894.         default:
  895.         return(FS_WRONG_TYPE);
  896.     }
  897.     /*
  898.      * Make the file look like a swap file so the local cache
  899.      * is bypassed.  Also flush back any modified data so
  900.      * page-ins get good stuff.
  901.      */
  902.     streamPtr->flags |= FS_SWAP;
  903.     }
  904.     /*
  905.      * Tell the file server what's going on.
  906.      */
  907.     if (status == SUCCESS) {
  908.     Proc_ControlBlock    *procPtr = Proc_GetEffectiveProc();
  909.     ioctl.command = IOC_MAP;
  910.     ioctl.inBuffer = (Address)&isMapped;
  911.     ioctl.inBufSize = sizeof(int);
  912.     ioctl.outBuffer = (Address) NIL;
  913.     ioctl.outBufSize = 0;
  914.     ioctl.format = mach_Format;
  915.     ioctl.procID = procPtr->processID;
  916.     ioctl.familyID = procPtr->familyID;
  917.     ioctl.uid = procPtr->effectiveUserID;
  918.     ioctl.flags = 0;
  919.     status = Fs_IOControl(streamPtr, &ioctl, &reply);
  920.     }
  921.     return(status);
  922. }
  923.  
  924. /*
  925.  *----------------------------------------------------------------------------
  926.  *
  927.  * Fs_GetFileHandle --
  928.  *
  929.  *    Return an opaque handle for a file, really a pointer to its I/O handle.
  930.  *    This is used for a subsequent call to Fs_GetSegPtr.
  931.  *
  932.  * Results:
  933.  *    A pointer to the I/O handle of the file.
  934.  *
  935.  * Side effects:
  936.  *    None.
  937.  *
  938.  *----------------------------------------------------------------------------
  939.  *
  940.  */
  941.  
  942. ClientData
  943. Fs_GetFileHandle(streamPtr)
  944.     Fs_Stream *streamPtr;
  945. {
  946.     return((ClientData)streamPtr->ioHandlePtr);
  947. }
  948.  
  949. /*
  950.  *----------------------------------------------------------------------------
  951.  *
  952.  * Fs_GetSegPtr --
  953.  *
  954.  *    Return a pointer to a pointer to the segment associated with this
  955.  *    file.
  956.  *
  957.  * Results:
  958.  *    A pointer to the segment associated with this file.
  959.  *
  960.  * Side effects:
  961.  *    None.
  962.  *
  963.  *----------------------------------------------------------------------------
  964.  *
  965.  */
  966.  
  967. Vm_Segment **
  968. Fs_GetSegPtr(fileHandle)
  969.     ClientData fileHandle;
  970. {
  971.     Fs_HandleHeader *hdrPtr = (Fs_HandleHeader *)fileHandle;
  972.     Vm_Segment    **segPtrPtr;
  973.  
  974.     assert(((unsigned int) fileHandle & WORD_ALIGN_MASK) == 0);
  975.     switch (hdrPtr->fileID.type) {
  976.     case FSIO_LCL_FILE_STREAM:
  977.         segPtrPtr = &(((Fsio_FileIOHandle *)hdrPtr)->segPtr);
  978.         break;
  979.     case FSIO_RMT_FILE_STREAM:
  980.         segPtrPtr = &(((Fsrmt_FileIOHandle *)hdrPtr)->segPtr);
  981.         break;
  982.     case FSIO_LCL_PFS_STREAM:
  983.     case FSIO_RMT_PFS_STREAM:
  984.         segPtrPtr = &(((Fspdev_ClientIOHandle *)hdrPtr)->segPtr);
  985.         break;
  986.     default:
  987.         segPtrPtr = (Vm_Segment **) NIL;
  988.         panic( "Fs_RetSegPtr, bad stream type %d\n",
  989.             hdrPtr->fileID.type);
  990.     }
  991.     fs_Stats.handle.segmentFetches++;
  992.     if (*segPtrPtr != (Vm_Segment *) NIL) {
  993.     fs_Stats.handle.segmentHits++;
  994.     }
  995.     return(segPtrPtr);
  996. }
  997.  
  998.